Introduction

This notebook…

Dependencies

This notebook requires…

# tidyverse packages
library(dplyr)       # data wrangling
library(readr)       # read/write tabular data
library(stringr)     # work with strings
library(tidyr)       # data wrangling
# spatial packages
library(janitor)     # data wrangling
library(sf)          # spatial data tools
library(mapview)     # projections
library(tigris)      # census data wrangling 
# other packages
library(here)        # file path management
library(naniar)      # missing data
library(ggplot2)
library(viridis)      # palettes
library(leaflet)
library(tidycensus) 
library(sp)
library(ggplot2)   
library(RColorBrewer)  # color palettes
library(viridis)       # color palettes

Load Data 2015

loading asthma data from MoPhim data base asthma is for 2015

asthma <- read_csv(here("data", "asthma.csv"))
Missing column names filled in: 'X3' [3]Parsed with column specification:
cols(
  `Title:` = col_character(),
  `Missouri EPHT Asthma` = col_character(),
  X3 = col_logical()
)
1031 parsing failures.
row col  expected    actual                                                                         file
  1  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma.csv'
  2  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma.csv'
  3  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma.csv'
  4  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma.csv'
  5  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma.csv'
... ... ......... ......... ............................................................................
See problems(...) for more details.

Getting rid of first three rows bc they are pointless text.

asthma %>%
  slice(4:1029) -> asthma_sliced

Getting rid of third col with no data. aslo renaming cols to ‘count’ and ‘zip’

asthma_sliced %>%
  select(-X3) %>%
  rename(count = `Missouri EPHT Asthma`) %>%
  rename(zip = `Title:`)-> asthma_sliced

Changing X to NA, making the count variable numeric

mutate(asthma_sliced, count = ifelse(count == "x", NA, count)) -> asthma_cleaned
mutate(asthma_sliced, count = as.numeric(count)) -> asthma_cleaned
NAs introduced by coercion

`

loading Mo zip codes

moZip <- zctas(state = "Missouri", year = 2010,
               cb = FALSE, class ="sf")
Using FIPS code '29' for state 'Missouri'
ZCTAs can take several minutes to download.  To cache the data and avoid re-downloading in future R sessions, set `options(tigris_use_cache = TRUE)`

Changing object to SF

st_as_sf(moZip) -> moZip

cleaning names, selecting just cols for zip and geometry, changing col name to zip

moZip %>%
  clean_names() %>%
  select(zcta5ce10, geometry) %>%
  rename(zip = `zcta5ce10`)-> moZip_clean

Load Data 2014

loading data for asthma 2014

asthma_14<- read_csv(here("data", "asthma2014.csv"))
Missing column names filled in: 'X3' [3]Parsed with column specification:
cols(
  `Title:` = col_character(),
  `Missouri EPHT Asthma` = col_character(),
  X3 = col_logical()
)
1031 parsing failures.
row col  expected    actual                                                                             file
  1  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2014.csv'
  2  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2014.csv'
  3  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2014.csv'
  4  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2014.csv'
  5  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2014.csv'
... ... ......... ......... ................................................................................
See problems(...) for more details.

getting rid of first three rows bc they have nothing in them

asthma_14 %>%
  slice(4:1029) -> asthma14_sliced

getting rid of empty third col, renaming remaning cols

asthma14_sliced %>%
  select(-X3) %>%
  rename(count = `Missouri EPHT Asthma`) %>%
  rename(zip = `Title:`) -> asthma14_sliced

changing X to NA, changing to numeric

mutate(asthma14_sliced, count = ifelse(count == "x", NA, count)) -> asthma14_cleaned
mutate(asthma14_sliced, count = as.numeric(count)) -> asthma14_cleaned
NAs introduced by coercion

left join to asthma_cleaned by zip. Now table has data for both 2014 and 2015

left_join(asthma_cleaned, asthma14_cleaned, by = "zip") -> joined_14_15

Load Data 2013

loading asthma data for 2013

asthma_2013 <- read_csv(here("data", "asthma2013.csv")) 
Missing column names filled in: 'X3' [3]Parsed with column specification:
cols(
  `Title:` = col_character(),
  `Missouri EPHT Asthma` = col_character(),
  X3 = col_logical()
)
1031 parsing failures.
row col  expected    actual                                                                             file
  1  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2013.csv'
  2  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2013.csv'
  3  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2013.csv'
  4  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2013.csv'
  5  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2013.csv'
... ... ......... ......... ................................................................................
See problems(...) for more details.

Getting rid of first 4 rows bc they have no data

asthma_2013 %>%
  slice(4:1029) -> asthma13_sliced

getting rid of third col, renaming other cols

asthma13_sliced %>%
  select(-X3) %>%
  rename(count_13 = `Missouri EPHT Asthma`) %>%
  rename(zip = `Title:`) -> asthma13_sliced

changing X to NA, changing count to numeric

mutate(asthma13_sliced, count_13 = ifelse(count_13 == "x", NA, count_13)) -> asthma13_cleaned
mutate(asthma13_sliced, count_13 = as.numeric(count_13)) -> asthma13_cleaned
NAs introduced by coercion

left joing to joined_14_15, so table now has data for years 2013, 2014, and 2015

left_join(joined_14_15, asthma13_cleaned, by = "zip") -> joined_13_14_15

Load Data 2012

loading data for 2012

asthma_2012 <- read_csv(here("data", "asthma2012.csv")) 

getting rid of empty cols

asthma_2012 %>%
  slice(4:1029) -> asthma12_sliced

cleaning data

asthma12_sliced %>%
  select(-X3) %>%
  rename(count_12 = `Missouri EPHT Asthma`) %>%
  rename(zip = `Title:`) -> asthma12_sliced
Error in is_character(x) : object 'X3' not found

changing X to NA and changing count to numeric

mutate(asthma12_sliced, count_12 = ifelse(count_12 == "x", NA, count_12)) -> asthma12_cleaned
mutate(asthma12_sliced, count_12 = as.numeric(count_12)) -> asthma12_cleaned
NAs introduced by coercion

left joing to joined_13_14_15 by zip. Table now has data for 2012 through 2015

left_join(joined_13_14_15, asthma12_cleaned, by = "zip") -> joined12_15

Load Data 2011

loading data for 2011

asthma_2011 <- read_csv(here("data", "asthma2011.csv")) 
Missing column names filled in: 'X3' [3]Parsed with column specification:
cols(
  `Title:` = col_character(),
  `Missouri EPHT Asthma` = col_character(),
  X3 = col_logical()
)
1031 parsing failures.
row col  expected    actual                                                                             file
  1  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2011.csv'
  2  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2011.csv'
  3  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2011.csv'
  4  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2011.csv'
  5  -- 3 columns 4 columns '/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/data/asthma2011.csv'
... ... ......... ......... ................................................................................
See problems(...) for more details.

getting rid of empty cols

asthma_2011 %>%
  slice(4:1029) -> asthma11_sliced

cleaning data

asthma11_sliced %>%
  select(-X3) %>%
  rename(count_11 = `Missouri EPHT Asthma`) %>%
  rename(zip = `Title:`) -> asthma11_sliced

changing X to NA, and changing count to be numeric

mutate(asthma11_sliced, count_11 = ifelse(count_11 == "x", NA, count_11)) -> asthma11_cleaned
mutate(asthma11_sliced, count_11 = as.numeric(count_11)) -> asthma11_cleaned
NAs introduced by coercion

Joining data for years 2011-2015

joining to joined_12_15 for years 2011-2015

left_join(joined12_15, asthma11_cleaned, by = "zip") -> joined11_15

joining data with geometry by zip

asthma_full_11_15 <- left_join(moZip_clean, joined11_15, by = "zip")
asthma_full_11_15 %>%
rename(
  count_14 = count.y,
  count_15 = count.x
) -> asthma_full_11_15

Zip codes for St Louis metro area

filtering for Zip codes in St Louis Metro Area, first filter gets range, Exclude gets rid of zip codes in that range that aren’t included in the metro area.

asthma_full_11_15 %>%
  filter(zip >= (63005))%>%
  filter(zip <= (63390)) -> asthma_metro
exclude <- c(63091, 63155, 63333, 63334, 63336, 63339, 63344, 63345, 63350, 63351, 63352, 63353, 63359, 63359, 63361, 63363, 63382, 63388, 63384, 63036, 63087, 63330)
asthma_metro %>%
filter(as.character(zip) %in% exclude == FALSE) -> asthma_metro_2

changing NA’s to 0s

asthma_metro_2 %>%
  mutate(count_11 = ifelse(is.na(count_11) == TRUE, 0, count_11)) %>%
  mutate(count_12 = ifelse(is.na(count_12) == TRUE, 0, count_12)) %>%
  mutate(count_13 = ifelse(is.na(count_13) == TRUE, 0, count_13)) %>%
  mutate(count_14 = ifelse(is.na(count_14) == TRUE, 0, count_14)) %>%
  mutate(count_15 = ifelse(is.na(count_15) == TRUE, 0, count_15))-> asthma_metro_2

Creating Count variable

Creating count for all 5 years

asthma_metro_2 %>%
  group_by(zip) %>%
  mutate(total = sum(count_15, count_14, count_13, count_12, count_11)) %>%
  select(zip, total, geometry) -> asthma_count_total

rowwise() %>% getting census data to get population for zip code tracts. using 5 year estimates from 2015

acs <- load_variables(year = 2015, dataset = "acs5", cache = TRUE)
pop <- get_acs(geography = "zip code tabulation area", year = 2015, variables = "B01003_001", survey = "acs5")
Getting data from the 2011-2015 5-year ACS

filtering for zip codes in st. louis metro area

pop %>%
  filter(GEOID >= (63005))%>%
  filter(GEOID <= (63390)) ->pop
pop %>%
  filter(as.character(GEOID) %in% exclude == FALSE)%>%
  rename(zip = GEOID,
         pop = estimate) %>%
  select(zip, pop) -> pop_metro

left join pop_metro to asthma_count_total, making variable for count

left_join(asthma_count_total, pop_metro, by = "zip") %>%
  mutate(count = (total/pop)*1000) %>%
 select(zip, count, geometry) -> count_by_pop
mapview(count_by_pop)

creating ggplot map

ggplot() +
    geom_sf(data = count_by_pop, mapping = aes(fill = count)) +
  scale_fill_distiller(palette = "Greens", trans ="reverse")

saving csv file for Asthma data for years 2011-2015

write.csv(count_by_pop, here("csv", "asthmaCount11_15.csv"))

loading Data for % African American

loading data for year 2015 (five year estimate)

aa <- get_acs(geography = "zip code tabulation area", year = 2015, variables = "B02009_001", survey = "acs5")
Getting data from the 2011-2015 5-year ACS

Joining with pop data

aa <- left_join(aa, pop, by = "GEOID") 

normalizing by pop

aa %>%
mutate(percent = estimate.x/estimate.y) %>%
  rename(zip = GEOID) -> aa

join with asthma data

aa_metro <- left_join(count_by_pop, aa, by = "zip")

saving csv file for % african american

write.csv(aa_metro, here("csv", "percent_aa.csv"))

saving as shapefile

dir.create(here("csv", "precent_aa"))
st_write(aa_metro, dsn = here("csv","precent_aa", "precent_aa.shp"), delete_dsn = TRUE)
GDAL Error 1: /Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/precent_aa/precent_aa.shp does not appear to be a file or directory.
Deleting source `/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/precent_aa/precent_aa.shp' failed
Writing layer `precent_aa' to data source `/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/precent_aa/precent_aa.shp' using driver `ESRI Shapefile'
features:       127
fields:         11
geometry type:  Multi Polygon

loading data for median income

loading five year estimate for 2015

median_income <- get_acs(geography = "zip code tabulation area", year = 2015, variables = "B06011_001", survey = "acs5")

join with pop data

median_income <- left_join(median_income, pop, by = "GEOID") 

normalize by pop

median_income%>%
mutate(percent = estimate.x/estimate.y) %>%
rename(zip = GEOID) -> median_income

join with asthma data

median_income <- left_join(count_by_pop, median_income, by = "zip")

saving csv file for median income

write.csv(median_income, here("csv", "median_income.csv"))

saving as shapefile

dir.create(here("csv", "median_income"))
st_write(median_income, dsn = here("csv","median_income", "median_income.shp"), delete_dsn = TRUE)
GDAL Error 1: /Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/median_income/median_income.shp does not appear to be a file or directory.
Deleting source `/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/median_income/median_income.shp' failed
Writing layer `median_income' to data source `/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/median_income/median_income.shp' using driver `ESRI Shapefile'
features:       127
fields:         11
geometry type:  Multi Polygon

loading data for median home value

loading 5 year estimate from 2015

home_value <- get_acs(geography = "zip code tabulation area", year = 2015, variables = "B25077_001", survey = "acs5")
Getting data from the 2011-2015 5-year ACS

joining with pop data

home_value <- left_join(home_value, pop, by = "GEOID") 

normalizing by pop

home_value%>%
mutate(percent = estimate.x/estimate.y) %>%
rename(zip = GEOID) -> home_value

joining with asthma data

home_metro <- left_join(count_by_pop, home_value, by = "zip")

Saving csv file for median home value

write.csv(home_metro, here("csv", "median_home.csv"))

saving as shapefile

dir.create(here("csv", "home_value"))
st_write(home_metro, dsn = here("csv","home_value", "home_value.shp"), delete_dsn = TRUE)
GDAL Error 1: /Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/home_value/home_value.shp does not appear to be a file or directory.
Deleting source `/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/home_value/home_value.shp' failed
Writing layer `home_value' to data source `/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/home_value/home_value.shp' using driver `ESRI Shapefile'
features:       127
fields:         11
geometry type:  Multi Polygon

loading data for medicaide

loading five year estimate from 2015

medicaid <- get_acs(geography = "zip code tabulation area", year = 2015, variables = "B992707_001", survey = "acs5")

joining with pop

medicaid <- left_join(medicaid, pop, by = "GEOID") 

normalizing by pop

medicaid %>%
mutate(percent = estimate.x/estimate.y) %>%
rename(zip = GEOID) -> medicaid

joining with asthma data

med_metro <- left_join(count_by_pop, medicaid, by = "zip")

saving csv file

write.csv(med_metro, here("csv", "medicaid.csv"))

saving as shapefile

dir.create(here("csv", "medicaid"))
st_write(med_metro, dsn = here("csv","medicaid", "medicaid.shp"), delete_dsn = TRUE)
GDAL Error 1: /Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/medicaid/medicaid.shp does not appear to be a file or directory.
Deleting source `/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/medicaid/medicaid.shp' failed
Writing layer `medicaid' to data source `/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/medicaid/medicaid.shp' using driver `ESRI Shapefile'
features:       127
fields:         10
geometry type:  Multi Polygon

loading data for % under poverty line

loading five year estimates for 2015

poverty <- get_acs(geography = "zip code tabulation area", year = 2015, variables = "B17001_002", survey = "acs5")

loading poverty total

poverty_total <- get_acs(geography = "zip code tabulation area", year = 2015, variables = "B17001_001", survey = "acs5")
poverty %>%
  select(GEOID, estimate) -> poverty
poverty <- left_join(poverty, poverty_total, by = "GEOID") 

normalizing by povery total

poverty %>%
  mutate(density = estimate.x/estimate.y) %>%
  rename(zip = GEOID) -> poverty

joining with asthma data

poverty_metro <- left_join(count_by_pop, poverty, by = "zip")

saving as csv file

write.csv(poverty_metro, here("csv", "poverty.csv"))
dir.create(here("csv", "poverty"))
st_write(poverty_metro, dsn = here("csv","poverty", "poverty.shp"), delete_dsn = TRUE)
GDAL Error 1: /Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/poverty/poverty.shp does not appear to be a file or directory.
Deleting source `/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/poverty/poverty.shp' failed
Writing layer `poverty' to data source `/Users/avagagner/Desktop/Courses/Fall 2019/Research/Asthma/csv/poverty/poverty.shp' using driver `ESRI Shapefile'
features:       127
fields:         8
geometry type:  Multi Polygon
LS0tCnRpdGxlOiAiQ2xlYW5pbmcgQXN0aG1hIERhdGEgIgphdXRob3I6ICJBdmEiCmRhdGU6ICcoYHIgZm9ybWF0KFN5cy50aW1lKCksICIlQiAlZCwgJVkiKWApJwpvdXRwdXQ6IAogIGdpdGh1Yl9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQgCi0tLQoKIyMgSW50cm9kdWN0aW9uClRoaXMgbm90ZWJvb2suLi4KCiMjIERlcGVuZGVuY2llcwpUaGlzIG5vdGVib29rIHJlcXVpcmVzLi4uCgpgYGB7ciBsb2FkLXBhY2thZ2VzfQojIHRpZHl2ZXJzZSBwYWNrYWdlcwpsaWJyYXJ5KGRwbHlyKSAgICAgICAjIGRhdGEgd3JhbmdsaW5nCmxpYnJhcnkocmVhZHIpICAgICAgICMgcmVhZC93cml0ZSB0YWJ1bGFyIGRhdGEKbGlicmFyeShzdHJpbmdyKSAgICAgIyB3b3JrIHdpdGggc3RyaW5ncwpsaWJyYXJ5KHRpZHlyKSAgICAgICAjIGRhdGEgd3JhbmdsaW5nCiMgc3BhdGlhbCBwYWNrYWdlcwpsaWJyYXJ5KGphbml0b3IpICAgICAjIGRhdGEgd3JhbmdsaW5nCmxpYnJhcnkoc2YpICAgICAgICAgICMgc3BhdGlhbCBkYXRhIHRvb2xzCmxpYnJhcnkobWFwdmlldykgICAgICMgcHJvamVjdGlvbnMKbGlicmFyeSh0aWdyaXMpICAgICAgIyBjZW5zdXMgZGF0YSB3cmFuZ2xpbmcgCiMgb3RoZXIgcGFja2FnZXMKbGlicmFyeShoZXJlKSAgICAgICAgIyBmaWxlIHBhdGggbWFuYWdlbWVudApsaWJyYXJ5KG5hbmlhcikgICAgICAjIG1pc3NpbmcgZGF0YQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkodmlyaWRpcykgICAgICAjIHBhbGV0dGVzCmxpYnJhcnkobGVhZmxldCkKbGlicmFyeSh0aWR5Y2Vuc3VzKSAKbGlicmFyeShzcCkKbGlicmFyeShnZ3Bsb3QyKSAgIApsaWJyYXJ5KFJDb2xvckJyZXdlcikgICMgY29sb3IgcGFsZXR0ZXMKbGlicmFyeSh2aXJpZGlzKSAgICAgICAjIGNvbG9yIHBhbGV0dGVzCgoKYGBgCgoKCiMjIExvYWQgRGF0YSAyMDE1CmxvYWRpbmcgYXN0aG1hIGRhdGEgZnJvbSBNb1BoaW0gZGF0YSBiYXNlCmFzdGhtYSBpcyBmb3IgMjAxNQoKYGBge3IgbG9hZC1kYXRhfQphc3RobWEgPC0gcmVhZF9jc3YoaGVyZSgiZGF0YSIsICJhc3RobWEuY3N2IikpCmBgYAoKCkdldHRpbmcgcmlkIG9mIGZpcnN0IHRocmVlIHJvd3MgYmMgdGhleSBhcmUgcG9pbnRsZXNzIHRleHQuIApgYGB7ciBwMS1xMX0KYXN0aG1hICU+JQogIHNsaWNlKDQ6MTAyOSkgLT4gYXN0aG1hX3NsaWNlZApgYGAKCkdldHRpbmcgcmlkIG9mIHRoaXJkIGNvbCB3aXRoIG5vIGRhdGEuIGFzbG8gcmVuYW1pbmcgY29scyB0byAnY291bnQnIGFuZCAnemlwJwpgYGB7cn0KYXN0aG1hX3NsaWNlZCAlPiUKICBzZWxlY3QoLVgzKSAlPiUKICByZW5hbWUoY291bnQgPSBgTWlzc291cmkgRVBIVCBBc3RobWFgKSAlPiUKICByZW5hbWUoemlwID0gYFRpdGxlOmApLT4gYXN0aG1hX3NsaWNlZApgYGAKCkNoYW5naW5nIFggdG8gTkEsIG1ha2luZyB0aGUgY291bnQgdmFyaWFibGUgbnVtZXJpYwpgYGB7cn0KbXV0YXRlKGFzdGhtYV9zbGljZWQsIGNvdW50ID0gaWZlbHNlKGNvdW50ID09ICJ4IiwgTkEsIGNvdW50KSkgLT4gYXN0aG1hX2NsZWFuZWQKYGBgCmBgYHtyfQptdXRhdGUoYXN0aG1hX3NsaWNlZCwgY291bnQgPSBhcy5udW1lcmljKGNvdW50KSkgLT4gYXN0aG1hX2NsZWFuZWQKYGBgCmAKCmxvYWRpbmcgTW8gemlwIGNvZGVzIApgYGB7cn0KbW9aaXAgPC0gemN0YXMoc3RhdGUgPSAiTWlzc291cmkiLCB5ZWFyID0gMjAxMCwKICAgICAgICAgICAgICAgY2IgPSBGQUxTRSwgY2xhc3MgPSJzZiIpCmBgYAoKQ2hhbmdpbmcgb2JqZWN0IHRvIFNGCmBgYHtyfQpzdF9hc19zZihtb1ppcCkgLT4gbW9aaXAKYGBgCgpjbGVhbmluZyBuYW1lcywgc2VsZWN0aW5nIGp1c3QgY29scyBmb3IgemlwIGFuZCBnZW9tZXRyeSwgY2hhbmdpbmcgY29sIG5hbWUgdG8gemlwCmBgYHtyfQptb1ppcCAlPiUKICBjbGVhbl9uYW1lcygpICU+JQogIHNlbGVjdCh6Y3RhNWNlMTAsIGdlb21ldHJ5KSAlPiUKICByZW5hbWUoemlwID0gYHpjdGE1Y2UxMGApLT4gbW9aaXBfY2xlYW4KYGBgCgojIyBMb2FkIERhdGEgMjAxNApsb2FkaW5nIGRhdGEgZm9yIGFzdGhtYSAyMDE0CmBgYHtyfQphc3RobWFfMTQ8LSByZWFkX2NzdihoZXJlKCJkYXRhIiwgImFzdGhtYTIwMTQuY3N2IikpCmBgYAoKZ2V0dGluZyByaWQgb2YgZmlyc3QgdGhyZWUgcm93cyBiYyB0aGV5IGhhdmUgbm90aGluZyBpbiB0aGVtIApgYGB7cn0KYXN0aG1hXzE0ICU+JQogIHNsaWNlKDQ6MTAyOSkgLT4gYXN0aG1hMTRfc2xpY2VkCmBgYAoKZ2V0dGluZyByaWQgb2YgZW1wdHkgdGhpcmQgY29sLCByZW5hbWluZyByZW1hbmluZyBjb2xzCmBgYHtyfQphc3RobWExNF9zbGljZWQgJT4lCiAgc2VsZWN0KC1YMykgJT4lCiAgcmVuYW1lKGNvdW50ID0gYE1pc3NvdXJpIEVQSFQgQXN0aG1hYCkgJT4lCiAgcmVuYW1lKHppcCA9IGBUaXRsZTpgKSAtPiBhc3RobWExNF9zbGljZWQKYGBgCgpjaGFuZ2luZyBYIHRvIE5BLCBjaGFuZ2luZyB0byBudW1lcmljCmBgYHtyfQptdXRhdGUoYXN0aG1hMTRfc2xpY2VkLCBjb3VudCA9IGlmZWxzZShjb3VudCA9PSAieCIsIE5BLCBjb3VudCkpIC0+IGFzdGhtYTE0X2NsZWFuZWQKYGBgCgpgYGB7cn0KbXV0YXRlKGFzdGhtYTE0X3NsaWNlZCwgY291bnQgPSBhcy5udW1lcmljKGNvdW50KSkgLT4gYXN0aG1hMTRfY2xlYW5lZApgYGAKbGVmdCBqb2luIHRvIGFzdGhtYV9jbGVhbmVkIGJ5IHppcC4gTm93IHRhYmxlIGhhcyBkYXRhIGZvciBib3RoIDIwMTQgYW5kIDIwMTUgCmBgYHtyfQpsZWZ0X2pvaW4oYXN0aG1hX2NsZWFuZWQsIGFzdGhtYTE0X2NsZWFuZWQsIGJ5ID0gInppcCIpIC0+IGpvaW5lZF8xNF8xNQpgYGAKCiMjIExvYWQgRGF0YSAyMDEzCmxvYWRpbmcgYXN0aG1hIGRhdGEgZm9yIDIwMTMgCmBgYHtyfQphc3RobWFfMjAxMyA8LSByZWFkX2NzdihoZXJlKCJkYXRhIiwgImFzdGhtYTIwMTMuY3N2IikpIApgYGAKR2V0dGluZyByaWQgb2YgZmlyc3QgNCByb3dzIGJjIHRoZXkgaGF2ZSBubyBkYXRhIApgYGB7cn0KYXN0aG1hXzIwMTMgJT4lCiAgc2xpY2UoNDoxMDI5KSAtPiBhc3RobWExM19zbGljZWQKYGBgCgpnZXR0aW5nIHJpZCBvZiB0aGlyZCBjb2wsIHJlbmFtaW5nIG90aGVyIGNvbHMKYGBge3J9CmFzdGhtYTEzX3NsaWNlZCAlPiUKICBzZWxlY3QoLVgzKSAlPiUKICByZW5hbWUoY291bnRfMTMgPSBgTWlzc291cmkgRVBIVCBBc3RobWFgKSAlPiUKICByZW5hbWUoemlwID0gYFRpdGxlOmApIC0+IGFzdGhtYTEzX3NsaWNlZApgYGAKCmNoYW5naW5nIFggdG8gTkEsIGNoYW5naW5nIGNvdW50IHRvIG51bWVyaWMgCmBgYHtyfQptdXRhdGUoYXN0aG1hMTNfc2xpY2VkLCBjb3VudF8xMyA9IGlmZWxzZShjb3VudF8xMyA9PSAieCIsIE5BLCBjb3VudF8xMykpIC0+IGFzdGhtYTEzX2NsZWFuZWQKYGBgCmBgYHtyfQptdXRhdGUoYXN0aG1hMTNfc2xpY2VkLCBjb3VudF8xMyA9IGFzLm51bWVyaWMoY291bnRfMTMpKSAtPiBhc3RobWExM19jbGVhbmVkCmBgYApsZWZ0IGpvaW5nIHRvIGpvaW5lZF8xNF8xNSwgc28gdGFibGUgbm93IGhhcyBkYXRhIGZvciB5ZWFycyAyMDEzLCAyMDE0LCBhbmQgMjAxNSAKYGBge3J9CmxlZnRfam9pbihqb2luZWRfMTRfMTUsIGFzdGhtYTEzX2NsZWFuZWQsIGJ5ID0gInppcCIpIC0+IGpvaW5lZF8xM18xNF8xNQpgYGAKCiMjIExvYWQgRGF0YSAyMDEyCmxvYWRpbmcgZGF0YSBmb3IgMjAxMiAKYGBge3J9CmFzdGhtYV8yMDEyIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEiLCAiYXN0aG1hMjAxMi5jc3YiKSkgCmBgYAoKZ2V0dGluZyByaWQgb2YgZW1wdHkgY29scwpgYGB7cn0KYXN0aG1hXzIwMTIgJT4lCiAgc2xpY2UoNDoxMDI5KSAtPiBhc3RobWExMl9zbGljZWQKYGBgCgpjbGVhbmluZyBkYXRhCmBgYHtyfQphc3RobWExMl9zbGljZWQgJT4lCiAgc2VsZWN0KC1YMykgJT4lCiAgcmVuYW1lKGNvdW50XzEyID0gYE1pc3NvdXJpIEVQSFQgQXN0aG1hYCkgJT4lCiAgcmVuYW1lKHppcCA9IGBUaXRsZTpgKSAtPiBhc3RobWExMl9zbGljZWQKYGBgCgpjaGFuZ2luZyBYIHRvIE5BIGFuZCBjaGFuZ2luZyBjb3VudCB0byBudW1lcmljIApgYGB7cn0KbXV0YXRlKGFzdGhtYTEyX3NsaWNlZCwgY291bnRfMTIgPSBpZmVsc2UoY291bnRfMTIgPT0gIngiLCBOQSwgY291bnRfMTIpKSAtPiBhc3RobWExMl9jbGVhbmVkCmBgYApgYGB7cn0KbXV0YXRlKGFzdGhtYTEyX3NsaWNlZCwgY291bnRfMTIgPSBhcy5udW1lcmljKGNvdW50XzEyKSkgLT4gYXN0aG1hMTJfY2xlYW5lZApgYGAKbGVmdCBqb2luZyB0byBqb2luZWRfMTNfMTRfMTUgYnkgemlwLiBUYWJsZSBub3cgaGFzIGRhdGEgZm9yIDIwMTIgdGhyb3VnaCAyMDE1IApgYGB7cn0KbGVmdF9qb2luKGpvaW5lZF8xM18xNF8xNSwgYXN0aG1hMTJfY2xlYW5lZCwgYnkgPSAiemlwIikgLT4gam9pbmVkMTJfMTUKYGBgCgojIyBMb2FkIERhdGEgMjAxMQpsb2FkaW5nIGRhdGEgZm9yIDIwMTEKYGBge3J9CmFzdGhtYV8yMDExIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEiLCAiYXN0aG1hMjAxMS5jc3YiKSkgCmBgYApnZXR0aW5nIHJpZCBvZiBlbXB0eSBjb2xzCmBgYHtyfQphc3RobWFfMjAxMSAlPiUKICBzbGljZSg0OjEwMjkpIC0+IGFzdGhtYTExX3NsaWNlZApgYGAKCmNsZWFuaW5nIGRhdGEKYGBge3J9CmFzdGhtYTExX3NsaWNlZCAlPiUKICBzZWxlY3QoLVgzKSAlPiUKICByZW5hbWUoY291bnRfMTEgPSBgTWlzc291cmkgRVBIVCBBc3RobWFgKSAlPiUKICByZW5hbWUoemlwID0gYFRpdGxlOmApIC0+IGFzdGhtYTExX3NsaWNlZApgYGAKCmNoYW5naW5nIFggdG8gTkEsIGFuZCBjaGFuZ2luZyBjb3VudCB0byBiZSBudW1lcmljIApgYGB7cn0KbXV0YXRlKGFzdGhtYTExX3NsaWNlZCwgY291bnRfMTEgPSBpZmVsc2UoY291bnRfMTEgPT0gIngiLCBOQSwgY291bnRfMTEpKSAtPiBhc3RobWExMV9jbGVhbmVkCmBgYAoKYGBge3J9Cm11dGF0ZShhc3RobWExMV9zbGljZWQsIGNvdW50XzExID0gYXMubnVtZXJpYyhjb3VudF8xMSkpIC0+IGFzdGhtYTExX2NsZWFuZWQKYGBgCgojIyBKb2luaW5nIGRhdGEgZm9yIHllYXJzIDIwMTEtMjAxNQpqb2luaW5nIHRvIGpvaW5lZF8xMl8xNSBmb3IgeWVhcnMgMjAxMS0yMDE1CmBgYHtyfQpsZWZ0X2pvaW4oam9pbmVkMTJfMTUsIGFzdGhtYTExX2NsZWFuZWQsIGJ5ID0gInppcCIpIC0+IGpvaW5lZDExXzE1CmBgYAoKam9pbmluZyBkYXRhIHdpdGggZ2VvbWV0cnkgYnkgemlwCmBgYHtyfQphc3RobWFfZnVsbF8xMV8xNSA8LSBsZWZ0X2pvaW4obW9aaXBfY2xlYW4sIGpvaW5lZDExXzE1LCBieSA9ICJ6aXAiKQpgYGAKYGBge3J9CmFzdGhtYV9mdWxsXzExXzE1ICU+JQpyZW5hbWUoCiAgY291bnRfMTQgPSBjb3VudC55LAogIGNvdW50XzE1ID0gY291bnQueAopIC0+IGFzdGhtYV9mdWxsXzExXzE1CmBgYAoKIyMgWmlwIGNvZGVzIGZvciBTdCBMb3VpcyBtZXRybyBhcmVhCgpmaWx0ZXJpbmcgZm9yIFppcCBjb2RlcyBpbiBTdCBMb3VpcyBNZXRybyBBcmVhLCBmaXJzdCBmaWx0ZXIgZ2V0cyByYW5nZSwgRXhjbHVkZSBnZXRzIHJpZCBvZiB6aXAgY29kZXMgaW4gdGhhdCByYW5nZSB0aGF0IGFyZW4ndCBpbmNsdWRlZCBpbiB0aGUgbWV0cm8gYXJlYS4gCmBgYHtyfQphc3RobWFfZnVsbF8xMV8xNSAlPiUKICBmaWx0ZXIoemlwID49ICg2MzAwNSkpJT4lCiAgZmlsdGVyKHppcCA8PSAoNjMzOTApKSAtPiBhc3RobWFfbWV0cm8KYGBgCgogIApgYGB7cn0KZXhjbHVkZSA8LSBjKDYzMDkxLCA2MzE1NSwgNjMzMzMsIDYzMzM0LCA2MzMzNiwgNjMzMzksIDYzMzQ0LCA2MzM0NSwgNjMzNTAsIDYzMzUxLCA2MzM1MiwgNjMzNTMsIDYzMzU5LCA2MzM1OSwgNjMzNjEsIDYzMzYzLCA2MzM4MiwgNjMzODgsIDYzMzg0LCA2MzAzNiwgNjMwODcsIDYzMzMwKQpgYGAKCmBgYHtyfQphc3RobWFfbWV0cm8gJT4lCmZpbHRlcihhcy5jaGFyYWN0ZXIoemlwKSAlaW4lIGV4Y2x1ZGUgPT0gRkFMU0UpIC0+IGFzdGhtYV9tZXRyb18yCmBgYAoKY2hhbmdpbmcgTkEncyB0byAwcwpgYGB7cn0KYXN0aG1hX21ldHJvXzIgJT4lCiAgbXV0YXRlKGNvdW50XzExID0gaWZlbHNlKGlzLm5hKGNvdW50XzExKSA9PSBUUlVFLCAwLCBjb3VudF8xMSkpICU+JQogIG11dGF0ZShjb3VudF8xMiA9IGlmZWxzZShpcy5uYShjb3VudF8xMikgPT0gVFJVRSwgMCwgY291bnRfMTIpKSAlPiUKICBtdXRhdGUoY291bnRfMTMgPSBpZmVsc2UoaXMubmEoY291bnRfMTMpID09IFRSVUUsIDAsIGNvdW50XzEzKSkgJT4lCiAgbXV0YXRlKGNvdW50XzE0ID0gaWZlbHNlKGlzLm5hKGNvdW50XzE0KSA9PSBUUlVFLCAwLCBjb3VudF8xNCkpICU+JQogIG11dGF0ZShjb3VudF8xNSA9IGlmZWxzZShpcy5uYShjb3VudF8xNSkgPT0gVFJVRSwgMCwgY291bnRfMTUpKS0+IGFzdGhtYV9tZXRyb18yCmBgYAoKCiMjIENyZWF0aW5nIENvdW50IHZhcmlhYmxlCkNyZWF0aW5nIGNvdW50IGZvciBhbGwgNSB5ZWFycwoKYGBge3J9CmFzdGhtYV9tZXRyb18yICU+JQogIGdyb3VwX2J5KHppcCkgJT4lCiAgbXV0YXRlKHRvdGFsID0gc3VtKGNvdW50XzE1LCBjb3VudF8xNCwgY291bnRfMTMsIGNvdW50XzEyLCBjb3VudF8xMSkpICU+JQogIHNlbGVjdCh6aXAsIHRvdGFsLCBnZW9tZXRyeSkgLT4gYXN0aG1hX2NvdW50X3RvdGFsCmBgYApyb3d3aXNlKCkgJT4lCmdldHRpbmcgY2Vuc3VzIGRhdGEgdG8gZ2V0IHBvcHVsYXRpb24gZm9yIHppcCBjb2RlIHRyYWN0cy4gdXNpbmcgNSB5ZWFyIGVzdGltYXRlcyBmcm9tIDIwMTUKYGBge3J9CmFjcyA8LSBsb2FkX3ZhcmlhYmxlcyh5ZWFyID0gMjAxNSwgZGF0YXNldCA9ICJhY3M1IiwgY2FjaGUgPSBUUlVFKQpgYGAKCmBgYHtyfQpwb3AgPC0gZ2V0X2FjcyhnZW9ncmFwaHkgPSAiemlwIGNvZGUgdGFidWxhdGlvbiBhcmVhIiwgeWVhciA9IDIwMTUsIHZhcmlhYmxlcyA9ICJCMDEwMDNfMDAxIiwgc3VydmV5ID0gImFjczUiKQpgYGAKCmZpbHRlcmluZyBmb3IgemlwIGNvZGVzIGluIHN0LiBsb3VpcyBtZXRybyBhcmVhCmBgYHtyfQpwb3AgJT4lCiAgZmlsdGVyKEdFT0lEID49ICg2MzAwNSkpJT4lCiAgZmlsdGVyKEdFT0lEIDw9ICg2MzM5MCkpIC0+cG9wCmBgYApgYGB7cn0KcG9wICU+JQogIGZpbHRlcihhcy5jaGFyYWN0ZXIoR0VPSUQpICVpbiUgZXhjbHVkZSA9PSBGQUxTRSklPiUKICByZW5hbWUoemlwID0gR0VPSUQsCiAgICAgICAgIHBvcCA9IGVzdGltYXRlKSAlPiUKICBzZWxlY3QoemlwLCBwb3ApIC0+IHBvcF9tZXRybwpgYGAKCmxlZnQgam9pbiBwb3BfbWV0cm8gdG8gYXN0aG1hX2NvdW50X3RvdGFsLCBtYWtpbmcgdmFyaWFibGUgZm9yIGNvdW50IApgYGB7cn0KbGVmdF9qb2luKGFzdGhtYV9jb3VudF90b3RhbCwgcG9wX21ldHJvLCBieSA9ICJ6aXAiKSAlPiUKICBtdXRhdGUoY291bnQgPSAodG90YWwvcG9wKSoxMDAwKSAlPiUKIHNlbGVjdCh6aXAsIGNvdW50LCBnZW9tZXRyeSkgLT4gY291bnRfYnlfcG9wCmBgYAoKYGBge3J9Cm1hcHZpZXcoY291bnRfYnlfcG9wKQpgYGAKCmNyZWF0aW5nIGdncGxvdCBtYXAKYGBge3J9CmdncGxvdCgpICsKICAgIGdlb21fc2YoZGF0YSA9IGNvdW50X2J5X3BvcCwgbWFwcGluZyA9IGFlcyhmaWxsID0gY291bnQpKSArCiAgc2NhbGVfZmlsbF9kaXN0aWxsZXIocGFsZXR0ZSA9ICJHcmVlbnMiLCB0cmFucyA9InJldmVyc2UiKQpgYGAKCiMjIHNhdmluZyBjc3YgZmlsZSBmb3IgQXN0aG1hIGRhdGEgZm9yIHllYXJzIDIwMTEtMjAxNQpgYGB7cn0Kd3JpdGUuY3N2KGNvdW50X2J5X3BvcCwgaGVyZSgiY3N2IiwgImFzdGhtYUNvdW50MTFfMTUuY3N2IikpCmBgYAoKCiMjIGxvYWRpbmcgRGF0YSBmb3IgJSBBZnJpY2FuIEFtZXJpY2FuIAoKbG9hZGluZyBkYXRhIGZvciB5ZWFyIDIwMTUgKGZpdmUgeWVhciBlc3RpbWF0ZSkKYGBge3J9CmFhIDwtIGdldF9hY3MoZ2VvZ3JhcGh5ID0gInppcCBjb2RlIHRhYnVsYXRpb24gYXJlYSIsIHllYXIgPSAyMDE1LCB2YXJpYWJsZXMgPSAiQjAyMDA5XzAwMSIsIHN1cnZleSA9ICJhY3M1IikKYGBgCgpKb2luaW5nIHdpdGggcG9wIGRhdGEKYGBge3J9CmFhIDwtIGxlZnRfam9pbihhYSwgcG9wLCBieSA9ICJHRU9JRCIpIApgYGAKCm5vcm1hbGl6aW5nIGJ5IHBvcApgYGB7cn0KYWEgJT4lCm11dGF0ZShwZXJjZW50ID0gZXN0aW1hdGUueC9lc3RpbWF0ZS55KSAlPiUKICByZW5hbWUoemlwID0gR0VPSUQpIC0+IGFhCmBgYAoKam9pbiB3aXRoIGFzdGhtYSBkYXRhIApgYGB7cn0KYWFfbWV0cm8gPC0gbGVmdF9qb2luKGNvdW50X2J5X3BvcCwgYWEsIGJ5ID0gInppcCIpCmBgYAoKc2F2aW5nIGNzdiBmaWxlIGZvciAlIGFmcmljYW4gYW1lcmljYW4gCmBgYHtyfQp3cml0ZS5jc3YoYWFfbWV0cm8sIGhlcmUoImNzdiIsICJwZXJjZW50X2FhLmNzdiIpKQpgYGAKCnNhdmluZyBhcyBzaGFwZWZpbGUKYGBge3J9CmRpci5jcmVhdGUoaGVyZSgiY3N2IiwgInByZWNlbnRfYWEiKSkKc3Rfd3JpdGUoYWFfbWV0cm8sIGRzbiA9IGhlcmUoImNzdiIsInByZWNlbnRfYWEiLCAicHJlY2VudF9hYS5zaHAiKSwgZGVsZXRlX2RzbiA9IFRSVUUpCmBgYAoKIyMgbG9hZGluZyBkYXRhIGZvciBtZWRpYW4gaW5jb21lCmxvYWRpbmcgZml2ZSB5ZWFyIGVzdGltYXRlIGZvciAyMDE1CmBgYHtyfQptZWRpYW5faW5jb21lIDwtIGdldF9hY3MoZ2VvZ3JhcGh5ID0gInppcCBjb2RlIHRhYnVsYXRpb24gYXJlYSIsIHllYXIgPSAyMDE1LCB2YXJpYWJsZXMgPSAiQjA2MDExXzAwMSIsIHN1cnZleSA9ICJhY3M1IikKYGBgCgpqb2luIHdpdGggcG9wIGRhdGEgCmBgYHtyfQptZWRpYW5faW5jb21lIDwtIGxlZnRfam9pbihtZWRpYW5faW5jb21lLCBwb3AsIGJ5ID0gIkdFT0lEIikgCgpgYGAKCm5vcm1hbGl6ZSBieSBwb3AKYGBge3J9Cm1lZGlhbl9pbmNvbWUlPiUKbXV0YXRlKHBlcmNlbnQgPSBlc3RpbWF0ZS54L2VzdGltYXRlLnkpICU+JQpyZW5hbWUoemlwID0gR0VPSUQpIC0+IG1lZGlhbl9pbmNvbWUKYGBgCgpqb2luIHdpdGggYXN0aG1hIGRhdGEgCmBgYHtyfQptZWRpYW5faW5jb21lIDwtIGxlZnRfam9pbihjb3VudF9ieV9wb3AsIG1lZGlhbl9pbmNvbWUsIGJ5ID0gInppcCIpCgpgYGAKCnNhdmluZyBjc3YgZmlsZSBmb3IgbWVkaWFuIGluY29tZSAKCmBgYHtyfQp3cml0ZS5jc3YobWVkaWFuX2luY29tZSwgaGVyZSgiY3N2IiwgIm1lZGlhbl9pbmNvbWUuY3N2IikpCmBgYAoKc2F2aW5nIGFzIHNoYXBlZmlsZQpgYGB7cn0KZGlyLmNyZWF0ZShoZXJlKCJjc3YiLCAibWVkaWFuX2luY29tZSIpKQpzdF93cml0ZShtZWRpYW5faW5jb21lLCBkc24gPSBoZXJlKCJjc3YiLCJtZWRpYW5faW5jb21lIiwgIm1lZGlhbl9pbmNvbWUuc2hwIiksIGRlbGV0ZV9kc24gPSBUUlVFKQpgYGAKCiMjIGxvYWRpbmcgZGF0YSBmb3IgbWVkaWFuIGhvbWUgdmFsdWUgCgpsb2FkaW5nIDUgeWVhciBlc3RpbWF0ZSBmcm9tIDIwMTUKYGBge3J9CmhvbWVfdmFsdWUgPC0gZ2V0X2FjcyhnZW9ncmFwaHkgPSAiemlwIGNvZGUgdGFidWxhdGlvbiBhcmVhIiwgeWVhciA9IDIwMTUsIHZhcmlhYmxlcyA9ICJCMjUwNzdfMDAxIiwgc3VydmV5ID0gImFjczUiKQpgYGAKCmpvaW5pbmcgd2l0aCBwb3AgZGF0YQpgYGB7cn0KaG9tZV92YWx1ZSA8LSBsZWZ0X2pvaW4oaG9tZV92YWx1ZSwgcG9wLCBieSA9ICJHRU9JRCIpIApgYGAKCm5vcm1hbGl6aW5nIGJ5IHBvcApgYGB7cn0KaG9tZV92YWx1ZSU+JQptdXRhdGUocGVyY2VudCA9IGVzdGltYXRlLngvZXN0aW1hdGUueSkgJT4lCnJlbmFtZSh6aXAgPSBHRU9JRCkgLT4gaG9tZV92YWx1ZQpgYGAKCmpvaW5pbmcgd2l0aCBhc3RobWEgZGF0YQpgYGB7cn0KaG9tZV9tZXRybyA8LSBsZWZ0X2pvaW4oY291bnRfYnlfcG9wLCBob21lX3ZhbHVlLCBieSA9ICJ6aXAiKQpgYGAKClNhdmluZyBjc3YgZmlsZSBmb3IgbWVkaWFuIGhvbWUgdmFsdWUKCmBgYHtyfQp3cml0ZS5jc3YoaG9tZV9tZXRybywgaGVyZSgiY3N2IiwgIm1lZGlhbl9ob21lLmNzdiIpKQpgYGAKCnNhdmluZyBhcyBzaGFwZWZpbGUgCmBgYHtyfQpkaXIuY3JlYXRlKGhlcmUoImNzdiIsICJob21lX3ZhbHVlIikpCnN0X3dyaXRlKGhvbWVfbWV0cm8sIGRzbiA9IGhlcmUoImNzdiIsImhvbWVfdmFsdWUiLCAiaG9tZV92YWx1ZS5zaHAiKSwgZGVsZXRlX2RzbiA9IFRSVUUpCmBgYAoKCiMjIGxvYWRpbmcgZGF0YSBmb3IgbWVkaWNhaWRlIApsb2FkaW5nIGZpdmUgeWVhciBlc3RpbWF0ZSBmcm9tIDIwMTUKYGBge3J9Cm1lZGljYWlkIDwtIGdldF9hY3MoZ2VvZ3JhcGh5ID0gInppcCBjb2RlIHRhYnVsYXRpb24gYXJlYSIsIHllYXIgPSAyMDE1LCB2YXJpYWJsZXMgPSAiQjk5MjcwN18wMDEiLCBzdXJ2ZXkgPSAiYWNzNSIpCgpgYGAKCmpvaW5pbmcgd2l0aCBwb3AKYGBge3J9Cm1lZGljYWlkIDwtIGxlZnRfam9pbihtZWRpY2FpZCwgcG9wLCBieSA9ICJHRU9JRCIpIAoKYGBgCm5vcm1hbGl6aW5nIGJ5IHBvcApgYGB7cn0KbWVkaWNhaWQgJT4lCm11dGF0ZShwZXJjZW50ID0gZXN0aW1hdGUueC9lc3RpbWF0ZS55KSAlPiUKcmVuYW1lKHppcCA9IEdFT0lEKSAtPiBtZWRpY2FpZApgYGAKam9pbmluZyB3aXRoIGFzdGhtYSBkYXRhCmBgYHtyfQptZWRfbWV0cm8gPC0gbGVmdF9qb2luKGNvdW50X2J5X3BvcCwgbWVkaWNhaWQsIGJ5ID0gInppcCIpCgpgYGAKCnNhdmluZyBjc3YgZmlsZQoKYGBge3J9CndyaXRlLmNzdihtZWRfbWV0cm8sIGhlcmUoImNzdiIsICJtZWRpY2FpZC5jc3YiKSkKYGBgCgpzYXZpbmcgYXMgc2hhcGVmaWxlCmBgYHtyfQpkaXIuY3JlYXRlKGhlcmUoImNzdiIsICJtZWRpY2FpZCIpKQpzdF93cml0ZShtZWRfbWV0cm8sIGRzbiA9IGhlcmUoImNzdiIsIm1lZGljYWlkIiwgIm1lZGljYWlkLnNocCIpLCBkZWxldGVfZHNuID0gVFJVRSkKYGBgCgojIyBsb2FkaW5nIGRhdGEgZm9yICUgdW5kZXIgcG92ZXJ0eSBsaW5lCgpsb2FkaW5nIGZpdmUgeWVhciBlc3RpbWF0ZXMgZm9yIDIwMTUKYGBge3J9CnBvdmVydHkgPC0gZ2V0X2FjcyhnZW9ncmFwaHkgPSAiemlwIGNvZGUgdGFidWxhdGlvbiBhcmVhIiwgeWVhciA9IDIwMTUsIHZhcmlhYmxlcyA9ICJCMTcwMDFfMDAyIiwgc3VydmV5ID0gImFjczUiKQpgYGAKbG9hZGluZyBwb3ZlcnR5IHRvdGFsCmBgYHtyfQpwb3ZlcnR5X3RvdGFsIDwtIGdldF9hY3MoZ2VvZ3JhcGh5ID0gInppcCBjb2RlIHRhYnVsYXRpb24gYXJlYSIsIHllYXIgPSAyMDE1LCB2YXJpYWJsZXMgPSAiQjE3MDAxXzAwMSIsIHN1cnZleSA9ICJhY3M1IikKYGBgCgpgYGB7cn0KcG92ZXJ0eSAlPiUKICBzZWxlY3QoR0VPSUQsIGVzdGltYXRlKSAtPiBwb3ZlcnR5CmBgYAoKCmBgYHtyfQpwb3ZlcnR5IDwtIGxlZnRfam9pbihwb3ZlcnR5LCBwb3ZlcnR5X3RvdGFsLCBieSA9ICJHRU9JRCIpIApgYGAKbm9ybWFsaXppbmcgYnkgcG92ZXJ5IHRvdGFsIApgYGB7cn0KcG92ZXJ0eSAlPiUKICBtdXRhdGUoZGVuc2l0eSA9IGVzdGltYXRlLngvZXN0aW1hdGUueSkgJT4lCiAgcmVuYW1lKHppcCA9IEdFT0lEKSAtPiBwb3ZlcnR5CmBgYAoKam9pbmluZyB3aXRoIGFzdGhtYSBkYXRhCmBgYHtyfQpwb3ZlcnR5X21ldHJvIDwtIGxlZnRfam9pbihjb3VudF9ieV9wb3AsIHBvdmVydHksIGJ5ID0gInppcCIpCmBgYAoKCnNhdmluZyBhcyBjc3YgZmlsZSAKYGBge3J9CndyaXRlLmNzdihwb3ZlcnR5X21ldHJvLCBoZXJlKCJjc3YiLCAicG92ZXJ0eS5jc3YiKSkKCmBgYAoKYGBge3J9CmRpci5jcmVhdGUoaGVyZSgiY3N2IiwgInBvdmVydHkiKSkKc3Rfd3JpdGUocG92ZXJ0eV9tZXRybywgZHNuID0gaGVyZSgiY3N2IiwicG92ZXJ0eSIsICJwb3ZlcnR5LnNocCIpLCBkZWxldGVfZHNuID0gVFJVRSkKYGBgCgoK